package org.uni_hi.muus.bluetooth;

import java.util.Vector;

import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;

public class BluetoothDiscovery extends Thread implements DiscoveryListener {
	
	private volatile boolean _block;
	
	private static BluetoothDiscovery _btdisc=null;
	
	private DiscoveryAgent _da=null;
	
	private Vector 
		_devices=null,
		_services=null;

	private int[] _transIDs;

	private Vector _MuuSdev=null;
	
	private BluetoothDiscovery() throws BluetoothStateException{
		_MuuSdev=new Vector();
		_devices=new Vector();
		_services=new Vector();
		_da=LocalDevice.getLocalDevice().getDiscoveryAgent();
		this.start();
	}
	
	private static BluetoothDiscovery getBluetoothDiscovery(){
		if(_btdisc==null){
			try {
				_btdisc=new BluetoothDiscovery();
			} catch (BluetoothStateException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return _btdisc;
	}
	
	private synchronized void startSearchForDevices(){
		_devices.removeAllElements();
		notify();
	}
	
	public static void searchDevices() throws BluetoothStateException{
		getBluetoothDiscovery().startSearchForDevices();
	}

	public void deviceDiscovered(RemoteDevice btDev, DeviceClass arg1) {
		if (_devices.indexOf(btDev) == -1) {
			_devices.addElement(btDev);
		}
	}

	public void inquiryCompleted(int type) {
		switch(type){
			case INQUIRY_COMPLETED:// search for devices completed, now search for services
				searchServices();
				break;
			case INQUIRY_TERMINATED:// report that inquiry was terminated
				unblock();
				break;
			case INQUIRY_ERROR:// report that an error occured
				unblock();
				break;
		}
	}
	
	private void searchServices(){
		_services.removeAllElements();
		if(_devices.size()!=0){
			RemoteDevice rd=null;
			_transIDs=new int[_devices.size()];
			for(int i=0;i<_devices.size();i++){
				rd=(RemoteDevice)_devices.elementAt(i);
				try {
					_transIDs[i]=_da.searchServices(BluetoothServer.ATTRIBUTE_SET,BluetoothServer.UUID_SET,rd,this);
				} catch (BluetoothStateException e) {
					_transIDs[i]=-1;
					e.printStackTrace();
				}
			}
		}else{
			unblock();
		}
	}

	public void serviceSearchCompleted(int transID, int respCode) {
		boolean allDone=true;
		for (int i = 0; i < _transIDs.length; i++) {
			if(_transIDs[i]!=-1){
				if (_transIDs[i] == transID) {
					_transIDs[i]=-1;
				}else{
					allDone=false;
				}
			}
		}
		if(allDone){
			_MuuSdev.removeAllElements();
			for(int i=0;i<_services.size();i++){
				_MuuSdev.addElement(((ServiceRecord)_services.elementAt(i)).getHostDevice());
			}
			unblock();
		}
	}
	
	private synchronized void unblock(){
		_block=false;
		notifyAll();
	}
	
	public static Vector getDeviceVector(){
		return getBluetoothDiscovery().getDevices();
	}
	
	public static Vector getServiceVector(){
		return getBluetoothDiscovery().getServices();
	}
	
	/**
	 * Returns the ServiceRecords for the found devices.
	 * Will block if a search is in progress.
	 * @return Vector containing ServiceRecords for discovered MuuServer-Devices.
	 */
	public synchronized Vector getServices(){
		while(_block){
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return _services;
	}
	
	/**
	 * Initializes a new Device-Search for MuuServer 
	 * and returns the results as available.
	 * @return a Vector containing MuuServer Devices.
	 */
	public synchronized Vector getDevices(){
		_block=true;
		try {
			_da.startInquiry(DiscoveryAgent.GIAC, this);
		} catch (BluetoothStateException e) {
			inquiryCompleted(INQUIRY_ERROR);
		}
		while(_block){
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return _MuuSdev;
	}

	public void servicesDiscovered(int transID, ServiceRecord[] servRec) {
		System.out.println(transID);
		for(int i=0;i<servRec.length;i++){
			System.out.println(servRec[i].toString());
			_services.addElement(servRec[i]);
		}
	}
	
	public static void cancelInquiry(){
		try {
			LocalDevice.getLocalDevice().getDiscoveryAgent().cancelInquiry(getBluetoothDiscovery());
		} catch (BluetoothStateException e) {
			e.printStackTrace();
		}
	}
}
